/*
 * campfire, formerly known as bandcampDirect
 * Copyright (C) 2020 Fynn Godau
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * Not affiliated with bandcamp, Incorporated.
 */

package godau.fynn.bandcampdirect.bandcamp;

import android.util.Log;
import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

public class Cart {

    private OkHttpClient client;

    private static String clientId;

    /**
     * Cart has its own client to catch client_id cookies.
     *
     * Generates cart from the internet synchronously.
     */
    public Cart() throws IOException, JSONException {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.cookieJar(new CookieJar() {
            @Override
            public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {

                if (clientId == null) {
                    for (Cookie cookie : cookies) {
                        if (cookie.name().equals("client_id")) {
                            clientId = cookie.value();
                            Log.d("CART", clientId);
                        }
                    }
                }

            }

            @Override
            public List<Cookie> loadForRequest(HttpUrl url) {
                return Collections.emptyList();
            }
        });

        client = builder.build();

        if (clientId == null) {
            get();
        }
    }

    public JSONObject get() throws IOException, JSONException {

        Request request = new Request.Builder()
                .url("https://bandcamp.com/cart/contents.js?client_id=" + clientId)
                .get()
                .cacheControl(CacheControl.FORCE_NETWORK)
                .build();

        Response response = client
                .newCall(request).execute();


        String responseString = response
                .body()
                .string();


        String jsonString = responseString.split("Cart\\.init_data = ")[1]
                .split("; *\n")[0];

        Log.d("CARTGET", jsonString);
        JSONObject json = new JSONObject(jsonString);
        return json;
    }

    public void add(char itemType, long itemId, double unitPrice, int quantity, String purchaseNote, long bandId) throws IOException, JSONException {
        /*
        curl 'https://bandcamp.com/cart/cb'
        --data 'req=add
        &item_type=a
        &item_id=2833347880
        &unit_price=4.0
        &quantity=2
        &purchase_note
        &band_id=1196681540
        &client_id=FBB62664B3770831AD4DA4DB529DEF58DD9D8EA321D5A17D65A693410FBD7172
        &sync_num=1' | jq
         */

        RequestBody requestBody = new FormBody.Builder()
                .add("req", "add")
                .add("item_type", String.valueOf(itemType))
                .add("item_id", String.valueOf(itemId))
                .add("unit_price", String.valueOf(unitPrice))
                .add("quantity", String.valueOf(quantity))
                .add("purchase_note", purchaseNote)
                .add("band_id", String.valueOf(bandId))
                .add("client_id", clientId)
                .add("sync_num", "101")
                .build();

        Request request = new Request.Builder()
                .url("https://bandcamp.com/cart/cb")
                .post(requestBody)
                .build();

        String responseString = client.newCall(request).execute().body().string();

        if (responseString.trim().equals("oops")) {
            throw new OopsException();
        } else if (new JSONObject(responseString).has("resync")) {
            throw new ResyncException();
        }

        Log.d("CARTADD", responseString);

    }

    public String getCheckoutUrl() {
        return "https://bandcamp.com/cart/checkout_start?client_id=" + clientId + "&return_url=campfire%3A%2F%2Fbandcamp.com&payment_pref=c";

        /*
        Querying this URL with payment_pref=c associates the preferred payment method (default is PayPal) to the
        client ID. However, the credit card payment interface is only displayed if this client id is sent to the
        checkout page as a cookie!
         */
    }

    public static void setClientId(String clientId) {
        Cart.clientId = clientId;
    }

    private static class OopsException extends IOException {
        public OopsException() {
            super("Bandcamp returned oops. This means the request went horribly wrong.");
        }
    }

    private static class ResyncException extends IOException {
        public ResyncException() {
            super("Bandcamp returned a JSON containing a resync value, this likely means that the request was not processed because the client is confused, i.e. out of sync." +
                    "\nThis happens for example when the item that was requested to be added to the cart is already added.");
        }

    }
}
